package com.wt.chat.file;

import com.wt.chat.exception.BaseException;
import com.wt.chat.file.ftp.FtpConfig;
import org.apache.commons.net.ftp.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

/**
 * @description
 * @author: wangtao
 * @date:16:25 2019/12/5
 * @email:taow02@jumei.com
 */
public class FtpFileStoreSystem implements FileStoreSystem {

	private static final Logger log = LoggerFactory.getLogger(FtpFileStoreSystem.class);

	private FtpConfig ftpConfig;

	public static final String DIRSPLIT = "/";

	private FTPClient ftpClient = null;

	/**
	 *
	 * 功能：上传文件附件到文件服务器
	 * @param buffIn:上传文件流
	 * @param fileName：保存文件名称
	 * @return
	 */
	private boolean doSave(InputStream buffIn, String fileName) {
		boolean returnValue = false;
		// 上传文件
		try {
			// 建立连接
			connectToServer();
			// 设置传输二进制文件
			setFileType(FTP.BINARY_FILE_TYPE);
			int reply = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftpClient.disconnect();
				throw new IOException("failed to connect to the FTP Server:" + ftpConfig.getIp());
			}
			ftpClient.enterLocalPassiveMode();
			//切换到上传目录
			String basePath = ftpConfig.getBaseDir();
			String filePath = "";
			if (!ftpClient.changeWorkingDirectory(basePath+filePath)) {
				//如果目录不存在创建目录
				String[] dirs = filePath.split(DIRSPLIT);
				String tempPath = basePath;
				for (String dir : dirs) {
					if (null == dir || "".equals(dir)) continue;
					tempPath += DIRSPLIT + dir;
					if (!ftpClient.changeWorkingDirectory(tempPath)) {
						if (!ftpClient.makeDirectory(tempPath)) {
							return returnValue;
						} else {
							ftpClient.changeWorkingDirectory(tempPath);
						}
					}
				}
			}
			// 上传文件到ftp
			returnValue = ftpClient.storeFile(fileName, buffIn);
			// 输出操作结果信息
			if (returnValue) {
				log.info("uploadToFtp INFO: upload file  to ftp : succeed!");
			} else {
				log.info("uploadToFtp INFO: upload file  to ftp : failed!");
			}
			buffIn.close();
			// 关闭连接
			closeConnect();
		} catch (FTPConnectionClosedException e) {
			log.error("ftp连接被关闭！", e);
		} catch (Exception e) {
			returnValue = false;
			log.error("ERR : upload file  to ftp : failed! ", e);
		} finally {
			try {
				if (buffIn != null) {
					buffIn.close();
				}
			} catch (Exception e) {
				log.error("ftp关闭输入流时失败！", e);
			}
			if (ftpClient.isConnected()) {
				closeConnect();
			}
		}
		return returnValue;
	}


	/**
	 *
	 * 功能：根据文件名称，下载文件流
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	public InputStream downloadFile(String filename) throws IOException {
		InputStream in = null;
		try {

			// 建立连接
			connectToServer();
			ftpClient.enterLocalPassiveMode();
			// 设置传输二进制文件
			setFileType(FTP.BINARY_FILE_TYPE);
			int reply = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftpClient.disconnect();
				throw new IOException("failed to connect to the FTP Server:" + ftpConfig.getIp());
			}
			ftpClient.changeWorkingDirectory(ftpConfig.getBaseDir());

			// ftp文件获取文件
			in = ftpClient.retrieveFileStream(filename);

		} catch (FTPConnectionClosedException e) {
			log.error("ftp连接被关闭！", e);
			throw e;
		} catch (Exception e) {
			log.error("ERR : upload file " + filename + " from ftp : failed!", e);
		}
		return in;
	}

	/**
	 * 设置传输文件的类型[文本文件或者二进制文件]
	 *
	 * @param fileType
	 *            --BINARY_FILE_TYPE、ASCII_FILE_TYPE
	 */
	private void setFileType(int fileType) {
		try {
			ftpClient.setFileType(fileType);
		} catch (Exception e) {
			log.error("ftp设置传输文件的类型时失败！", e);
		}
	}

	/**
	 *
	 * 功能：关闭连接
	 */
	public void closeConnect() {
		try {
			if (ftpClient != null) {
				ftpClient.logout();
				ftpClient.disconnect();
			}
		} catch (Exception e) {
			log.error("ftp连接关闭失败！", e);
		}
	}

	/**
	 * 连接到ftp服务器
	 */
	private void connectToServer() throws Exception {
		if (!ftpClient.isConnected()) {
			int reply;
			try {
				ftpClient = new FTPClient();
				ftpClient.connect(ftpConfig.getIp(), ftpConfig.getPort());
				ftpClient.login(ftpConfig.getUserName(), ftpConfig.getPassWord());
				reply = ftpClient.getReplyCode();

				if (!FTPReply.isPositiveCompletion(reply)) {
					ftpClient.disconnect();
					log.info("connectToServer FTP server refused connection.");
				}

			} catch (FTPConnectionClosedException ex) {
				log.error("服务器:IP：" + ftpConfig.getIp() + "没有连接数！there are too many connected users,please try later",
						ex);
				throw ex;
			} catch (Exception e) {
				log.error("登录ftp服务器【" + ftpConfig.getIp() + "】失败", e);
				throw e;
			}
		}
	}

	public boolean existDirectory(String path) throws IOException {
		boolean flag = false;
		FTPFile[] ftpFileArr = ftpClient.listFiles(path);
		for (FTPFile ftpFile : ftpFileArr) {
			if (ftpFile.isDirectory() && ftpFile.getName().equalsIgnoreCase(path)) {
				flag = true;
				break;
			}
		}
		return flag;
	}

	/**
	 * 创建FTP文件夹目录
	 * @param pathName
	 * @return
	 * @throws IOException
	 */
	public boolean createDirectory(String pathName) throws IOException {
		boolean isSuccess = false;
		try {
			isSuccess = ftpClient.makeDirectory(pathName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return isSuccess;
	}

	/**
	 *
	 * 功能：根据当前时间获取文件目录
	 * @return String
	 */
	public static String getDateDir(Date dateParam) {
		Calendar cal = Calendar.getInstance();
		if (null != dateParam) {
			cal.setTime(dateParam);
		}
		int currentYear = cal.get(Calendar.YEAR);
		int currentMouth = cal.get(Calendar.MONTH) + 1;
		int currentDay = cal.get(Calendar.DAY_OF_MONTH);
		return currentYear + DIRSPLIT + currentMouth + DIRSPLIT + currentDay;
	}

	@Override
	public String save(InputStream is, String sourceFileName) {
		String randomFileName = UUID.randomUUID().toString().replace("-", "") + sourceFileName.substring(sourceFileName.lastIndexOf("."));
		if (doSave(is, randomFileName)) {
			return ftpConfig.getBaseDir() + DIRSPLIT + randomFileName;
		}
		throw new BaseException("FTP 文件上传失败");
	}

	@Override
	public InputStream get(String path) {
		try {
			return downloadFile(path);
		} catch (IOException e) {
			log.error("FTP 文件下载失败", e);
			throw new BaseException("FTP 文件下载失败" + e.getMessage());
		}
	}

}
